package com.clp.protocol.modbus_tcp.client.async;

import com.clp.protocol.core.common.async.IFutureListener;
import com.clp.protocol.modbus_tcp.client.ModbusClient;

import java.util.LinkedList;
import java.util.List;

public class AbstarctClientPromise<P extends AbstarctClientPromise<P, V>, V> implements ClientPromise<V> {

    protected volatile boolean isDone = false;
    protected volatile boolean isSuccess = false;
    protected volatile V val = null;
    protected volatile Throwable cause = null;
    protected final List<IFutureListener<ClientFuture<V>>> listeners = new LinkedList<>();

    private final ModbusClient client;

    protected AbstarctClientPromise(ModbusClient client) {
        this.client = client;
    }

    @Override
    public ModbusClient client() {
        return client;
    }

    @SuppressWarnings("unchecked")
    protected P self() {
        return ((P) this);
    }

    @Override
    public boolean isDone() {
        return isDone;
    }

    @Override
    public boolean isSuccess() {
        return isDone() && isSuccess;
    }

    @Override
    public V getRes() {
        return val;
    }

    @Override
    public P setRes(V val) {
        synchronized (this) {
            this.val = val;
            return self();
        }
    }

    /**
     * 只会设置一次，重复设置第2次无效
     *
     * @return
     */
    @Override
    public P setSuccess() {
        synchronized (this) {
            if (this.isDone()) return self();
            this.isSuccess = true;
            this.isDone = true;

            notifyAllListeners();
            this.notifyAll();
            return self();
        }
    }

    /**
     * 只会设置一次，重复设置第2次无效
     *
     * @param cause
     * @return
     */
    @Override
    public P setFailure(Throwable cause) {
        synchronized (this) {
            if (this.isDone()) return self();
            this.isSuccess = false;
            this.cause = cause;
            this.isDone = true;

            notifyAllListeners();
            this.notifyAll();
            return self();
        }
    }

    @Override
    public P sync(int timeoutMs) {
        synchronized (this) {
            long beginMs = System.currentTimeMillis();
            long passedMs = 0;
            while (!isDone()) {
                long waitMs = timeoutMs - passedMs;
                if (waitMs <= 0) break;
                try {
                    this.wait(waitMs);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                passedMs = System.currentTimeMillis() - beginMs;
            }
        }
        return self();
    }

    @Override
    public P addListener(IFutureListener<ClientFuture<V>> listener) {
        synchronized (this) {
            listeners.add(listener);
            if (this.isDone()) {
                notifyAllListeners();
            }
            return self();
        }
    }

    /**
     * 通知所有监听器
     */
    protected void notifyAllListeners() {
        synchronized (this) {
            for (IFutureListener<ClientFuture<V>> listener : listeners) {
                listener.operationComplete(self());
            }
            listeners.clear();
        }
    }

    @Override
    public P sync() {
        synchronized (this) {
            while (!isDone()) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return self();
        }
    }

    @Override
    public Throwable cause() {
        return cause;
    }
}
